import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import json
import os
from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
import webbrowser
import base64
import socket
import time
import uuid  # 添加 UUID 导入
import cgi  # 添加 cgi 模块用于解析 form-data
import tempfile  # 添加 tempfile 模块用于处理上传文件

class MockHandler(BaseHTTPRequestHandler):
    mock_data = {}  # 类变量，用于存储mock数据
    server = None  # 类变量，用于存储服务器实例
    log_callback = None  # 新增：用于记录请求日志的回调函数
    is_shutting_down = False  # 新增：用于标记服务器是否正在关闭
    
    def parse_multipart(self):
        """解析 multipart/form-data 请求"""
        content_type = self.headers.get('Content-Type', '')
        if not content_type.startswith('multipart/form-data'):
            return None
            
        try:
            form = cgi.FieldStorage(
                fp=self.rfile,
                headers=self.headers,
                environ={
                    'REQUEST_METHOD': 'POST',
                    'CONTENT_TYPE': self.headers['Content-Type'],
                }
            )
            return form
        except Exception as e:
            print(f"解析 multipart/form-data 失败: {str(e)}")
            return None
    
    def do_GET(self):
        self.handle_request()
        
    def do_POST(self):
        self.handle_request()
        
    def do_PUT(self):
        self.handle_request()
        
    def do_DELETE(self):
        self.handle_request()
        
    def do_PATCH(self):
        self.handle_request()
        
    def do_HEAD(self):
        self.handle_request()
        
    def do_OPTIONS(self):
        self.handle_request()
        
    def do_TRACE(self):
        self.handle_request()
        
    def do_CONNECT(self):
        self.handle_request()
        
    def handle_request(self):
        # 只获取路径的基本部分，忽略查询参数
        path = self.path.split('?')[0].lstrip('/')
        print(f"收到请求: {path}, 方法: {self.command}")
        
        # 如果是 OPTIONS 请求，返回支持的方法
        if self.command == 'OPTIONS':
            self.send_response(200)
            self.send_header('Access-Control-Allow-Origin', '*')
            self.send_header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE, CONNECT')
            self.send_header('Access-Control-Allow-Headers', '*')
            self.end_headers()
            return
            
        # 处理 multipart/form-data 请求
        if self.command == 'POST' and self.headers.get('Content-Type', '').startswith('multipart/form-data'):
            form = self.parse_multipart()
            if form:
                # 记录表单数据
                form_data = {}
                for field in form.keys():
                    if form[field].filename:
                        form_data[field] = f"File: {form[field].filename}"
                    else:
                        form_data[field] = form[field].value
                
                if MockHandler.log_callback and not MockHandler.is_shutting_down:
                    request_info = f"接口: {path} >>> 方法: {self.command}\n参数: {json.dumps(form_data, ensure_ascii=False, indent=2)}"
                    MockHandler.log_callback(request_info)
                
                # 处理响应
                if path in self.mock_data or f"/{path}" in self.mock_data:
                    try:
                        response_data = self.mock_data.get(path, self.mock_data.get(f"/{path}"))['response']
                        self.send_response(200)
                        self.send_header('Content-type', 'application/json; charset=utf-8')
                        self.send_header('Access-Control-Allow-Origin', '*')
                        self.send_header('Access-Control-Allow-Methods', '*')
                        self.send_header('Access-Control-Allow-Headers', '*')
                        self.end_headers()
                        self.wfile.write(response_data.encode())
                        return
                    except Exception as e:
                        print(f"处理响应时出错: {str(e)}")
                        self.send_error(500, "Internal Server Error")
                        return
        
        # 处理其他请求
        content_length = int(self.headers.get('Content-Length', 0))
        post_data = self.rfile.read(content_length).decode('utf-8') if content_length > 0 else ''
        
        if MockHandler.log_callback and not MockHandler.is_shutting_down:
            request_info = f"接口: {path} >>> 方法: {self.command}\n参数: {self.headers}{post_data}"
            MockHandler.log_callback(request_info)
        
        # 处理停止服务器的请求
        if path == 'stop':
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.send_header('Access-Control-Allow-Origin', '*')
            self.send_header('Access-Control-Allow-Methods', '*')
            self.send_header('Access-Control-Allow-Headers', '*')
            self.end_headers()
            try:
                MockHandler.is_shutting_down = True
                self.wfile.write(json.dumps({"message": "服务器正在停止"}).encode())
                self.wfile.flush()
                threading.Thread(target=self.shutdown_server).start()
            except (socket.error, ConnectionAbortedError):
                pass
            return
        
        if MockHandler.is_shutting_down:
            return
            
        print(f"当前mock_data: {self.mock_data}")
        
        # 尝试不带斜杠的路径
        if path in self.mock_data:
            try:
                response_data = self.mock_data[path]['response']
                self.send_response(200)
                self.send_header('Content-type', 'application/json; charset=utf-8')
                self.send_header('Access-Control-Allow-Origin', '*')
                self.send_header('Access-Control-Allow-Methods', '*')
                self.send_header('Access-Control-Allow-Headers', '*')
                self.end_headers()
                if self.command != 'HEAD':
                    self.wfile.write(response_data.encode())
            except Exception as e:
                print(f"处理响应时出错: {str(e)}")
                self.send_error(500, "Internal Server Error")
        # 尝试带斜杠的路径
        elif f"/{path}" in self.mock_data:
            try:
                response_data = self.mock_data[f"/{path}"]['response']
                self.send_response(200)
                self.send_header('Content-type', 'application/json; charset=utf-8')
                self.send_header('Access-Control-Allow-Origin', '*')
                self.send_header('Access-Control-Allow-Methods', '*')
                self.send_header('Access-Control-Allow-Headers', '*')
                self.end_headers()
                if self.command != 'HEAD':
                    self.wfile.write(response_data.encode())
            except Exception as e:
                print(f"处理响应时出错: {str(e)}")
                self.send_error(500, "Internal Server Error")
        else:
            self.send_error(404, "Not Found")
            
    def shutdown_server(self):
        """安全地关闭服务器"""
        try:
            if self.server:
                self.server.shutdown()
                self.server.server_close()
        except Exception as e:
            print(f"关闭服务器时出错: {str(e)}")
            
    def log_error(self, format, *args):
        """重写错误日志方法，忽略连接中断错误"""
        if "Connection aborted" not in format % args and "socket operation on non-socket" not in format % args:
            super().log_error(format, *args)

class MockServer:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("接口响应模拟器")
        self.root.geometry("1200x800")
        
        # 数据存储
        self.mock_data = {}
        self.load_mock_data()
        print(f"初始化时加载的mock_data: {self.mock_data}")
        
        # HTTP服务器
        self.server = None
        self.server_thread = None
        self.port = 5000
        
        # 创建主框架
        self.create_main_frame()
        
    def create_main_frame(self):
        # 顶部搜索框框架
        search_frame = ttk.Frame(self.root)
        search_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(search_frame, text="搜索接口:").pack(side=tk.LEFT)
        self.search_entry = ttk.Entry(search_frame)
        self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        self.search_entry.bind('<Return>', lambda event: self.search_interface())  # 绑定回车键
        ttk.Button(search_frame, text="搜索", command=self.search_interface).pack(side=tk.LEFT, padx=5)
        
        # 左侧框架
        left_frame = ttk.Frame(self.root)
        left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
        
        # 左侧按钮框架
        left_button_frame = ttk.Frame(left_frame)
        left_button_frame.pack(fill=tk.X, pady=(0, 5))
        
        ttk.Button(left_button_frame, text="新建文件夹", command=self.add_folder).pack(side=tk.LEFT, padx=5)
        ttk.Button(left_button_frame, text="删除文件夹", command=self.delete_folder).pack(side=tk.LEFT, padx=5)
        
        # 左侧树形结构
        self.tree = ttk.Treeview(left_frame, show='tree', style='Custom.Treeview')
        self.tree.pack(fill=tk.BOTH, expand=True, pady=(0, 5))
        self.tree.bind('<<TreeviewSelect>>', self.on_select)
        
        # 设置树形结构的样式
        style = ttk.Style()
        style.configure("Custom.Treeview", indent=20)  # 设置缩进大小
        style.configure("Custom.Treeview", padding=0)  # 移除内边距
        style.configure("Custom.Treeview", borderwidth=0)  # 移除边框
        
        # 创建图标
        self.folder_icon = "📁"  # 文件夹图标
        self.interface_icon = "🔗"  # 接口图标
        
        # 右侧框架
        right_frame = ttk.Frame(self.root)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 右侧详情
        ttk.Label(right_frame, text="接口名称:").pack(anchor=tk.W)
        self.name_entry = ttk.Entry(right_frame)
        self.name_entry.pack(fill=tk.X, padx=5, pady=2)
        
        ttk.Label(right_frame, text="接口路径:").pack(anchor=tk.W)
        self.path_entry = ttk.Entry(right_frame)
        self.path_entry.pack(fill=tk.X, padx=5, pady=2)
        
        ttk.Label(right_frame, text="响应结果:").pack(anchor=tk.W)
        self.response_text = tk.Text(right_frame, height=10)
        self.response_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=2)
        
        # 按钮框架
        button_frame = ttk.Frame(right_frame)
        button_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(button_frame, text="保存", command=self.save_mock).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="删除", command=self.delete_mock).pack(side=tk.LEFT, padx=5)
        
        # 服务器控制
        server_frame = ttk.Frame(right_frame)
        server_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Label(server_frame, text="端口:").pack(side=tk.LEFT)
        self.port_entry = ttk.Entry(server_frame, width=10)
        self.port_entry.insert(0, str(self.port))
        self.port_entry.pack(side=tk.LEFT, padx=5)
        
        # 设置按钮样式
        style.configure("Green.TButton", background="green")
        style.configure("Red.TButton", background="red")
        style.configure("Yellow.TButton", background="yellow")
        
        self.server_button = ttk.Button(server_frame, text="启动服务器", style="Green.TButton", command=self.toggle_server)
        self.server_button.pack(side=tk.LEFT, padx=5)
        
        # 请求日志框架
        log_frame = ttk.Frame(right_frame)
        log_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 日志标题和清空按钮框架
        log_header_frame = ttk.Frame(log_frame)
        log_header_frame.pack(fill=tk.X, padx=5, pady=2)
        
        ttk.Label(log_header_frame, text="请求日志:").pack(side=tk.LEFT)
        ttk.Button(log_header_frame, text="清空日志", command=self.clear_log).pack(side=tk.RIGHT)
        
        self.log_text = tk.Text(log_frame, height=10)
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=2)
        
        # 设置请求日志的回调
        MockHandler.log_callback = self.log_request
        
        # 刷新树形结构
        self.refresh_tree()
        
    def load_mock_data(self):
        try:
            self.mock_data = {}
            current_folder = None
            
            with open('mock_data.txt', 'r', encoding='utf-8') as f:
                lines = f.readlines()
                
            i = 0
            while i < len(lines):
                line = lines[i].strip()
                if not line or line.startswith('#'):  # 跳过空行和注释
                    i += 1
                    continue
                    
                if line.startswith('[') and line.endswith(']'):  # 文件夹
                    folder_name = line[1:-1]
                    self.mock_data[folder_name] = {
                        "type": "folder",
                        "children": {}
                    }
                    current_folder = folder_name
                    i += 1
                elif current_folder and line.startswith('path='):  # 接口路径
                    path = line[5:]
                    name = ''
                    response = ''
                    
                    # 读取接口名称
                    i += 1
                    if i < len(lines):
                        next_line = lines[i].strip()
                        if next_line.startswith('name='):
                            name = next_line[5:]
                            i += 1
                    
                    # 读取响应内容（支持多行）
                    response_lines = []
                    while i < len(lines):
                        content_line = lines[i].strip()
                        if not content_line:  # 遇到空行结束
                            i += 1
                            break
                        if content_line.startswith('[') or content_line.startswith('path='):  # 遇到新的接口或文件夹结束
                            break
                        response_lines.append(lines[i])
                        i += 1
                    response = ''.join(response_lines).strip()
                    
                    # 使用 UUID 作为键
                    interface_id = str(uuid.uuid4())
                    self.mock_data[current_folder]["children"][interface_id] = {
                        "name": name,
                        "path": path,  # 保留路径信息
                        "response": response
                    }
                else:
                    i += 1
        except FileNotFoundError:
            self.mock_data = {
                "默认文件夹": {
                    "type": "folder",
                    "children": {}
                }
            }
            self.save_mock_data()
            
    def save_mock_data(self):
        # 按文件夹名称排序
        folder_names = sorted(self.mock_data.keys())
        
        with open('mock_data.txt', 'w', encoding='utf-8') as f:
            f.write('# 接口响应模拟器配置文件\n')
            f.write('# 格式说明：\n')
            f.write('# [文件夹名称]\n')
            f.write('# path=接口路径\n')
            f.write('# name=接口名称\n')
            f.write('# 响应内容（支持多行）\n\n')
            
            for folder_name in folder_names:
                folder_data = self.mock_data[folder_name]
                f.write(f'[{folder_name}]\n')
                
                # 遍历所有接口
                for interface_id, api_data in folder_data["children"].items():
                    f.write(f'path={api_data["path"]}\n')
                    f.write(f'name={api_data["name"]}\n')
                    f.write(f'{api_data["response"]}\n\n')
            
    def refresh_tree(self):
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        def add_items(parent, data):
            items = []  # 存储所有添加的项目ID
            for name, item in data.items():
                if item.get("type") == "folder":
                    folder_id = self.tree.insert(parent, 'end', text=name, values=(name,), tags=('folder',))
                    items.append(folder_id)
                    # 递归添加子项目，并获取子项目的ID
                    child_items = add_items(folder_id, item.get("children", {}))
                    items.extend(child_items)
                else:
                    # 使用接口名称作为显示文本，使用 UUID 作为 values
                    interface_name = item.get('name', '')
                    interface_id = self.tree.insert(parent, 'end', text=f"{self.interface_icon} {interface_name}", 
                                                 values=(name,), tags=('interface',))  # name 就是 UUID
                    items.append(interface_id)
            return items
        
        # 添加所有项目并获取它们的ID
        all_items = add_items('', self.mock_data)
        
        # 展开所有项目
        for item_id in all_items:
            self.tree.item(item_id, open=True)
        
        self.tree.tag_configure('folder', foreground='#0066cc', font=('Arial', 10, 'bold'))  # 蓝色加粗
        self.tree.tag_configure('interface', foreground='#666666', font=('Arial', 9))  # 灰色普通
            
    def on_select(self, event):
        selected = self.tree.selection()
        if not selected:
            return
            
        item = self.tree.item(selected[0])
        path = item['values'][0]
        
        # 如果是文件夹，不显示详情
        if 'folder' in item['tags']:
            self.name_entry.delete(0, tk.END)
            self.path_entry.delete(0, tk.END)
            self.response_text.delete('1.0', tk.END)
            return
            
        # 获取完整路径（不包含文件夹名）
        item_path = self.get_item_path(selected[0])
        data = self.get_mock_data_by_path(item_path)
        if data:
            self.name_entry.delete(0, tk.END)
            self.name_entry.insert(0, data.get('name', ''))
            
            self.path_entry.delete(0, tk.END)
            # 获取接口的实际路径
            for folder_name, folder_data in self.mock_data.items():
                if folder_data.get("type") == "folder":
                    for interface_id, api_data in folder_data["children"].items():
                        if api_data.get('name') == data.get('name'):
                            self.path_entry.insert(0, api_data['path'])
                            break
            
            self.response_text.delete('1.0', tk.END)
            self.response_text.insert('1.0', data.get('response', ''))
            
    def get_mock_data_by_path(self, path):
        # path现在是一个列表，不需要split
        current = self.mock_data
        for part in path[:-1]:  # 遍历除最后一个元素外的所有部分
            if part in current and current[part].get("type") == "folder":
                current = current[part]["children"]
            else:
                return None
        return current.get(path[-1])
        
    def add_folder(self):
        folder_name = tk.simpledialog.askstring("新建文件夹", "请输入文件夹名称:")
        if folder_name:
            # 文件夹只能创建在根目录下
            self.mock_data[folder_name] = {
                "type": "folder",
                "children": {}
            }
            self.save_mock_data()
            self.refresh_tree()
            
    def delete_folder(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showerror("错误", "请选择要删除的文件夹")
            return
            
        item = self.tree.item(selected[0])
        if 'folder' not in item['tags']:
            messagebox.showerror("错误", "请选择文件夹")
            return
            
        if messagebox.askyesno("确认", f"确定要删除文件夹 {item['values'][0]} 吗？\n注意：文件夹中的所有接口也会被删除！"):
            path = self.get_item_path(selected[0])
            current = self.mock_data
            for part in path[:-1]:
                current = current[part]["children"]
            del current[path[-1]]
            self.save_mock_data()
            self.refresh_tree()
            
    def get_item_path(self, item):
        path = []
        while item:
            path.insert(0, self.tree.item(item)['values'][0])
            item = self.tree.parent(item)
        return path
        
    def save_mock(self):
        path = self.path_entry.get()
        if not path:
            messagebox.showerror("错误", "请输入接口路径")
            return
            
        response_text = self.response_text.get('1.0', tk.END).strip()
        print(f"保存接口: {path}")
        print(f"响应内容: {response_text}")
        
        # 确保路径以斜杠开头
        if not path.startswith('/'):
            path = f"/{path}"
            
        # 获取选中的文件夹或接口
        selected = self.tree.selection()
        if not selected:
            messagebox.showerror("错误", "请先选择一个文件夹或接口")
            return

        item = self.tree.item(selected[0])
        if 'folder' in item['tags']:
            # 如果选中的是文件夹，保存为新接口
            folder_path = self.get_item_path(selected[0])
            current = self.mock_data
            for part in folder_path[:-1]:  # 不包含最后一个文件夹名
                if part not in current or current[part].get("type") != "folder":
                    messagebox.showerror("错误", "无效的文件夹路径")
                    return
                current = current[part]["children"]

            # 确保文件夹有 children 字典
            if folder_path[-1] not in current:
                current[folder_path[-1]] = {
                    "type": "folder",
                    "children": {}
                }
            elif "children" not in current[folder_path[-1]]:
                current[folder_path[-1]]["children"] = {}

            # 使用 UUID 作为键
            interface_id = str(uuid.uuid4())
            current[folder_path[-1]]["children"][interface_id] = {
                'name': self.name_entry.get(),
                'path': path,
                'response': response_text
            }
        elif 'interface' in item['tags']:
            # 如果选中的是接口，更新接口信息
            item_path = self.get_item_path(selected[0])
            current = self.mock_data
            for part in item_path[:-1]:
                if part not in current or current[part].get("type") != "folder":
                    messagebox.showerror("错误", "无效的接口路径")
                    return
                current = current[part]["children"]

            # 更新接口信息
            current[item_path[-1]]['name'] = self.name_entry.get()
            current[item_path[-1]]['path'] = path
            current[item_path[-1]]['response'] = response_text
            interface_id = item_path[-1]  # 保存接口ID用于后续选中
        else:
            messagebox.showerror("错误", "请选择一个文件夹或接口")
            return

        self.save_mock_data()
        self.refresh_tree()

        # 如果服务器正在运行，更新MockHandler的mock_data
        if self.server:
            # 构建扁平化的mock_data用于服务器
            flat_mock_data = {}
            for folder_name, folder_data in self.mock_data.items():
                if folder_data.get("type") == "folder":
                    for interface_id, api_data in folder_data.get("children", {}).items():
                        flat_mock_data[api_data['path'].lstrip('/')] = api_data

            MockHandler.mock_data = flat_mock_data
            print(f"更新MockHandler的mock_data: {MockHandler.mock_data}")

        messagebox.showinfo("成功", "保存成功")
        
        # 选中新创建或更新的接口
        if 'folder' in item['tags']:
            # 如果是新建接口，使用新生成的 interface_id
            self.select_interface_by_id(folder_path[-1], interface_id)
        else:
            # 如果是更新接口，使用原有的 interface_id
            self.select_interface_by_id(item_path[-2], interface_id)
            
    def select_interface_by_id(self, folder_name, interface_id):
        """根据文件夹名称和接口ID选中接口"""
        # 在树形结构中查找文件夹
        for folder_item in self.tree.get_children():
            if self.tree.item(folder_item)['values'][0] == folder_name:
                # 在文件夹中查找接口
                for interface_item in self.tree.get_children(folder_item):
                    if self.tree.item(interface_item)['values'][0] == interface_id:
                        self.tree.selection_set(interface_item)
                        self.tree.see(interface_item)
                        self.on_select(None)
                        return
        
    def delete_mock(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showerror("错误", "请先选择要删除的接口")
            return
            
        item = self.tree.item(selected[0])
        if 'folder' in item['tags']:
            messagebox.showerror("错误", "请选择要删除的接口，而不是文件夹")
            return
            
        # 获取接口名称
        interface_name = self.name_entry.get()
        if not interface_name:
            interface_name = "未命名接口"
            
        if messagebox.askyesno("确认删除", f"确定要删除接口 {interface_name} 吗？"):
            item_path = self.get_item_path(selected[0])
            current = self.mock_data
            for part in item_path[:-1]:
                if part not in current or current[part].get("type") != "folder":
                    messagebox.showerror("错误", "无效的接口路径")
                    return
                current = current[part]["children"]
                
            if item_path[-1] in current:
                del current[item_path[-1]]
                self.save_mock_data()
                self.refresh_tree()
                self.clear_form()
                messagebox.showinfo("成功", "删除成功")
            else:
                messagebox.showerror("错误", "接口不存在")
            
    def run_server(self):
        # 构建扁平化的mock_data用于服务器
        flat_mock_data = {}
        for folder_name, folder_data in self.mock_data.items():
            if folder_data.get("type") == "folder":
                for interface_id, api_data in folder_data.get("children", {}).items():
                    flat_mock_data[api_data['path'].lstrip('/')] = api_data
        
        # 更新MockHandler的mock_data
        MockHandler.mock_data = flat_mock_data
        print(f"启动服务器时的mock_data: {MockHandler.mock_data}")
        
        self.server = HTTPServer(('127.0.0.1', self.port), MockHandler)
        MockHandler.server = self.server  # 设置服务器实例
        self.server.serve_forever()
        
    def stop_server(self):
        """在单独的线程中停止服务器"""
        try:
            # 先设置关闭标志
            MockHandler.is_shutting_down = True
            # 关闭服务器
            if self.server:
                self.server.shutdown()
                self.server.server_close()
            # 等待服务器线程结束
            if self.server_thread and self.server_thread.is_alive():
                self.server_thread.join(timeout=2)
        except Exception as e:
            print(f"停止服务器时出错: {str(e)}")
        finally:
            self.server = None
            self.server_thread = None
            MockHandler.is_shutting_down = False
            # 使用 after 方法在主线程中更新 UI
            self.root.after(0, lambda: self.server_button.config(text="启动服务器", style="Green.TButton"))

    def toggle_server(self):
        if self.server:
            # 停止服务器
            self.server_button.config(text="正在停止...", style="Yellow.TButton")
            # 在新线程中执行停止操作
            threading.Thread(target=self.stop_server, daemon=True).start()
        else:
            # 启动服务器
            try:
                self.port = int(self.port_entry.get())
            except ValueError:
                messagebox.showerror("错误", "请输入有效的端口号")
                return
                
            self.server_thread = threading.Thread(target=self.run_server)
            self.server_thread.daemon = True
            self.server_thread.start()
            self.server_button.config(text="停止服务器", style="Red.TButton")
            webbrowser.open(f'http://localhost:{self.port}')
            
    def log_request(self, request_info):
        self.log_text.insert(tk.END, request_info + "\n")
        self.log_text.insert(tk.END, "-" * 50 + "\n")  # 添加分割线
        self.log_text.see(tk.END)
        
    def search_interface(self):
        search_term = self.search_entry.get().strip()
        if not search_term:
            messagebox.showwarning("警告", "请输入搜索内容")
            return
        
        # 搜索匹配的接口
        results = []
        for folder_name, folder_data in self.mock_data.items():
            if folder_data.get("type") == "folder":
                for interface_id, api_data in folder_data["children"].items():
                    # 使用完全匹配
                    if search_term == api_data['path']:
                        results.append((folder_name, interface_id, api_data))
        
        # 显示搜索结果并选中
        if results:
            # 选中第一个匹配的结果
            first_result = results[0]
            folder, interface_id, data = first_result
            
            # 在树形结构中找到并选中该项
            for item in self.tree.get_children():
                self.tree.selection_remove(item)
            
            def find_and_select_item(parent_item, target_folder, target_id):
                # 如果是根目录，遍历所有文件夹
                if not parent_item:
                    for folder_item in self.tree.get_children():
                        if self.tree.item(folder_item)['values'][0] == target_folder:
                            # 找到文件夹后，搜索其子项
                            for child in self.tree.get_children(folder_item):
                                if self.tree.item(child)['values'][0] == target_id:
                                    self.tree.selection_set(child)
                                    self.tree.see(child)
                                    self.on_select(None)
                                    return True
                return False
            
            # 从根目录开始搜索
            if not find_and_select_item('', folder, interface_id):
                print(f"未能在树形结构中找到接口: folder={folder}, interface_id={interface_id}")
        else:
            messagebox.showinfo("搜索结果", "未找到匹配的接口")
        
    def run(self):
        self.root.mainloop()

    def clear_log(self):
        """清空日志内容"""
        self.log_text.delete('1.0', tk.END)

if __name__ == '__main__':
    app = MockServer()
    app.run() 